﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.IO;

namespace DbfReader
{
    public class DbfFileReader
    {
        private string version;
        private string modifyDate;
        private int recordCount;
        private Int16 fileHeadLength;
        private Int16 recordLength;
        private byte[] unUse1;
        private byte dBaseIvTransactionFlag;
        private byte dBaseIvEncryptionFlag;
        private byte[] reservedForMultiUser;
        private byte productionMdxFlag;
        private int languageDriveId;
        private byte[] unUse2;
        List<RecordDescription> recordDescriptions;
        byte recordTerminalTag;

        public DbfFileReader()
        {
            recordDescriptions = new List<RecordDescription>();
        }

        public DataTable Read(string dbfFile)
        {
            DataTable dataTable = null;
            FileStream filestream = null;

            try
            {
                filestream = new FileStream(dbfFile, FileMode.Open);
                dataTable = new DataTable();
                BinaryReader binaryReader = new BinaryReader(filestream);

                // Read the head of dbf.
                version = binaryReader.ReadByte().ToString();
                byte year = binaryReader.ReadByte();
                byte month = binaryReader.ReadByte();
                byte day = binaryReader.ReadByte();
                modifyDate = ((int)year + 1900).ToString() + " " + month.ToString() + day.ToString();
                recordCount = binaryReader.ReadInt32();
                fileHeadLength = binaryReader.ReadInt16();
                recordLength = binaryReader.ReadInt16();
                unUse1 = binaryReader.ReadBytes(2);
                dBaseIvTransactionFlag = binaryReader.ReadByte();
                dBaseIvEncryptionFlag = binaryReader.ReadByte();
                reservedForMultiUser = binaryReader.ReadBytes(12);
                productionMdxFlag = binaryReader.ReadByte();
                languageDriveId = (int)binaryReader.ReadByte();
                unUse2 = binaryReader.ReadBytes(2);

                // Read the record description.
                int columnCount = (fileHeadLength - 33) / 32;
                DataColumn dataColumn = null;
                for (int i = 0; i < columnCount; i++)
                {
                    RecordDescription recordDescription = new RecordDescription();
                    recordDescription.Read(binaryReader);
                    recordDescriptions.Add(recordDescription);
                    dataColumn = new DataColumn(recordDescription.recordName);
                    switch (recordDescription.recordType)
                    {
                        case 'C':
                            dataColumn.DataType = Type.GetType("System.String");
                            break;
                        case 'N':
                            dataColumn.DataType = Type.GetType("System.String");
                            // dataColumn.DataType = Type.GetType("System.Double");                       
                            break;
                        case 'F':
                            dataColumn.DataType = Type.GetType("System.String");
                            break;
                        case 'D':
                            break;
                        case 'G':
                            break;
                        case 'B':
                            break;
                        case 'L':
                            break;
                        case 'M':
                            break;
                        default:
                            break;
                    }
                    dataTable.Columns.Add(dataColumn);
                }
                recordTerminalTag = binaryReader.ReadByte();

                // Read the record data.
                for (int i = 0; i < recordCount; i++)
                {
                    char space = binaryReader.ReadChar();
                    DataRow dataRow = dataTable.NewRow();
                    for (int j = 0; j < columnCount; j++)
                    {
                        byte[] temp = binaryReader.ReadBytes(recordDescriptions[j].recordItemLength);
                        dataRow[j] = Encoding.Default.GetString(temp).Trim();
                    }
                    dataTable.Rows.Add(dataRow);
                }
          //      binaryReader.Close();
            }
            finally
            {
                filestream.Close();
            }
            return dataTable;
        }
    }
}
